import { BadRequestException, Injectable } from '@nestjs/common';
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { UserLogin } from 'src/user/entities/user-login.entity';
import { User } from 'src/user/entities/user.entity';
import { Between, EntityManager, Repository } from 'typeorm';
import { EnterpriseSearchStats } from './entities/enterpriseSearchStats.entity';
import { TopKeywords } from './entities/topKeywords .entity';
import { DailyCommentStats } from './entities/dailyCommentStats.entity';
import {
  startOfMonth,
  endOfMonth,
  eachDayOfInterval,
  eachMonthOfInterval,
  format,
} from 'date-fns';
import { DailyKeyStats } from './entities/dailyKeyStats.entity';

@Injectable()
export class StatisticService {
  @InjectRepository(UserLogin)
  private userLoginRepository: Repository<UserLogin>;

  @InjectRepository(EnterpriseSearchStats)
  private enterpriseSearchStatsRepository: Repository<EnterpriseSearchStats>;
  @InjectRepository(TopKeywords)
  private topKeywordsRepository: Repository<TopKeywords>;
  @InjectRepository(DailyCommentStats)
  private dailyCommentStatsRepository: Repository<DailyCommentStats>;

  @InjectRepository(DailyKeyStats)
  private dailyKeyStatsRepository: Repository<DailyKeyStats>;

  // 日活跃数

  async getDAU(startDate: string, endDate: string) {
    const start = new Date(startDate);
    const end = new Date(endDate);
    end.setHours(23, 59, 59, 999);

    const dates = eachDayOfInterval({ start, end }).map((date) =>
      format(date, 'yyyy-MM-dd'),
    );

    const dauCounts = await this.userLoginRepository
      .createQueryBuilder('user_login')
      .select('DATE(user_login.login_date)', 'date')
      .addSelect('COUNT(DISTINCT user_login.user_id)', 'dau')
      .where('user_login.login_date >= :startDate', { startDate: start })
      .andWhere('user_login.login_date <= :endDate', { endDate: end })
      .groupBy('DATE(user_login.login_date)')
      .getRawMany();

    const dauData = dauCounts.reduce((acc, item) => {
      const formattedDate = format(new Date(item.date), 'yyyy-MM-dd');
      acc[formattedDate] = item.dau;
      return acc;
    }, {});

    const result = dates.map((date) => ({
      date,
      dau: dauData[date] || '0',
    }));

    return result;
  }

  // 月活跃数
  async getMAU(startMonth: string, endMonth: string) {
    const start = new Date(startMonth);
    const end = new Date(endMonth);

    // 生成月份列表
    const months = eachMonthOfInterval({ start, end }).map((date) =>
      format(date, 'yyyy-MM'),
    );

    // 确保 startMonth 和 endMonth 格式正确
    const startMonthStr = format(start, 'yyyy-MM-01');
    const endMonthStr = format(end, 'yyyy-MM-31');

    // 查询 MAU
    const mauCounts = await this.userLoginRepository
      .createQueryBuilder('user_login')
      .select('DATE_FORMAT(user_login.login_date, "%Y-%m")', 'month')
      .addSelect('COUNT(DISTINCT user_login.user_id)', 'mau')
      .where('DATE_FORMAT(user_login.login_date, "%Y-%m") >= :startMonth', {
        startMonth: format(start, 'yyyy-MM'),
      })
      .andWhere('DATE_FORMAT(user_login.login_date, "%Y-%m") <= :endMonth', {
        endMonth: format(end, 'yyyy-MM'),
      })
      .groupBy('month')
      .getRawMany();

    // 处理数据
    const mauData = mauCounts.reduce((acc, item) => {
      acc[item.month] = item.mau;
      return acc;
    }, {});

    return months.map((month) => ({
      month,
      mau: mauData[month] || '0',
    }));
  }

  // 留存率
  async getRetentionRate(date: string, daysAfter: string) {
    const today = new Date();
    const selectedDate = new Date(date);

    // 将 daysAfter 字符串分割成数组
    const daysArray = daysAfter.split(',').map(Number);

    // 检查每个目标日期是否在未来
    for (const days of daysArray) {
      const targetDate = new Date(selectedDate);
      targetDate.setDate(targetDate.getDate() + days);

      if (targetDate > today) {
        throw new BadRequestException(
          `选择的日期加上留存天数 ${days} 天不能超过今天。请重新选择合法的日期范围。`,
        );
      }
    }

    const retentionRates = [];

    // 计算每个天数的留存率
    for (const days of daysArray) {
      // 1. 获取基准日的时间范围
      const startOfDay = new Date(date);
      startOfDay.setHours(0, 0, 0, 0);

      const endOfDay = new Date(date);
      endOfDay.setHours(23, 59, 59, 999);

      // 2. 获取目标日期的时间范围（基准日 + X 天）
      const startOfTargetDay = new Date(date);
      startOfTargetDay.setDate(startOfTargetDay.getDate() + days);
      startOfTargetDay.setHours(0, 0, 0, 0);

      const endOfTargetDay = new Date(date);
      endOfTargetDay.setDate(endOfTargetDay.getDate() + days);
      endOfTargetDay.setHours(23, 59, 59, 999);

      // 3. 查询基准日登录的用户
      const firstDayUsers = await this.userLoginRepository
        .createQueryBuilder('user_login')
        .select('DISTINCT user_login.user_id') // 只获取用户 ID
        .where('user_login.login_date >= :startOfDay', { startOfDay })
        .andWhere('user_login.login_date <= :endOfDay', { endOfDay })
        .getRawMany();

      const firstDayUserIds = firstDayUsers.map((user) => user.user_id); // 提取用户 ID

      if (firstDayUserIds.length === 0) {
        retentionRates.push({ days, retentionRate: 0 });
        continue; // 如果基准日没有用户，跳过当前天数
      }

      // 4. 查询目标日期仍然活跃的用户（回归用户）
      const retainedUsers = await this.userLoginRepository
        .createQueryBuilder('user_login')
        .select('DISTINCT user_login.user_id') // 只获取用户 ID
        .where('user_login.login_date >= :startOfTargetDay', {
          startOfTargetDay,
        })
        .andWhere('user_login.login_date <= :endOfTargetDay', {
          endOfTargetDay,
        })
        .andWhere('user_login.user_id IN (:...userIds)', {
          userIds: firstDayUserIds,
        }) // 仅统计基准日用户
        .getRawMany();

      const retainedUserCount = retainedUsers.length; // 回归用户数量

      // 5. 计算留存率
      const retentionRate = (retainedUserCount / firstDayUserIds.length) * 100;
      retentionRates.push({ days, retentionRate });
    }

    return { date, retentionRates };
  }

  // 查询关键词
  async getTopKeywords() {
    return await this.topKeywordsRepository.find({
      order: { searchCount: 'DESC' },
      take: 10,
    });
  }
  // 查询浏览的企业
  async getTopSearchedEnterprises() {
    return await this.enterpriseSearchStatsRepository.find({
      relations: ['enterprise'],
      order: { searchCount: 'DESC' },
      take: 10,
    });
  }
  // 查询评论数
  async getDailyCommentStats(startDate?: string, endDate?: string) {
    let queryStartDate = startDate;
    let queryEndDate = endDate;
    // 如果没有传递日期参数，则默认查询最近五天的数据
    if (!startDate || !endDate) {
      const today = new Date();
      queryEndDate = today.toISOString().split('T')[0]; // 获取今天的日期（YYYY-MM-DD 格式）
      const fiveDaysAgo = new Date(today);
      fiveDaysAgo.setDate(today.getDate() - 5); // 计算5天前的日期
      queryStartDate = fiveDaysAgo.toISOString().split('T')[0]; // 获取5天前的日期（YYYY-MM-DD 格式）
    }
    const data = await this.dailyCommentStatsRepository.find({
      where: {
        date: Between(queryStartDate, queryEndDate), // 使用 Between 操作符查询日期范围
      },
      order: { date: 'ASC' }, // 按日期升序排列
    });
    // 生成日期范围内的所有日期
    const dateRange = this.getDateRange(queryStartDate, queryEndDate);

    // 对比数据，确保每一天都有数据
    const result = dateRange.map((date) => {
      const existingData = data.find((item) => item.date === date);
      return existingData ? existingData : { date, commentCount: 0 }; // 如果没有数据，则返回 commentCount 为 0
    });

    return result;
  }

  // 查询搜索次数
  async getDailyKeyStats(startDate?: string, endDate?: string) {
    let queryStartDate = startDate;
    let queryEndDate = endDate;
    if (!startDate || !endDate) {
      const today = new Date();
      queryEndDate = today.toISOString().split('T')[0]; // 获取今天的日期（YYYY-MM-DD 格式）
      const fiveDaysAgo = new Date(today);
      fiveDaysAgo.setDate(today.getDate() - 5); // 计算5天前的日期
      queryStartDate = fiveDaysAgo.toISOString().split('T')[0]; // 获取5天前的日期（YYYY-MM-DD 格式）
    }

    // 获取指定日期范围内的数据
    const data = await this.dailyKeyStatsRepository.find({
      where: {
        date: Between(queryStartDate, queryEndDate),
      },
      order: { date: 'ASC' },
    });

    // 生成日期范围内的所有日期
    const dateRange = this.getDateRange(queryStartDate, queryEndDate);

    // 对比数据，确保每一天都有数据
    const result = dateRange.map((date) => {
      const existingData = data.find((item) => item.date === date);
      return existingData ? existingData : { date, keyCount: 0 }; // 如果没有数据，则返回 keyCount 为 0
    });

    return result;
  }
  private getDateRange(startDate: string, endDate: string): string[] {
    const dateRange = [];
    let currentDate = new Date(startDate);
    const end = new Date(endDate);

    while (currentDate <= end) {
      dateRange.push(currentDate.toISOString().split('T')[0]); // 将日期格式化为 YYYY-MM-DD
      currentDate.setDate(currentDate.getDate() + 1); // 增加一天
    }

    return dateRange;
  }
}
